home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / text / misc / nenscript1_3.lha / main.c < prev    next >
C/C++ Source or Header  |  1993-03-22  |  17KB  |  680 lines

  1. /*
  2.  *   $Id: main.c,v 1.3 1992/10/07 22:06:08 craigs Exp $
  3.  *
  4.  *   This code was written by Craig Southeren whilst under contract
  5.  *   to Computer Sciences of Australia, Systems Engineering Division.
  6.  *   It has been kindly released by CSA into the public domain.
  7.  *
  8.  *   Neither CSA or me guarantee that this source code is fit for anything,
  9.  *   so use it at your peril. I don't even work for CSA any more, so
  10.  *   don't bother them about it. If you have any suggestions or comments
  11.  *   (or money, cheques, free trips =8^) !!!!! ) please contact me
  12.  *   care of geoffw@extro.ucc.oz.au
  13.  *
  14.  */
  15.  
  16. #include "machdep.h"
  17. #include "defs.h"
  18.  
  19. #include "version.h"
  20. #include "print.h"
  21. #include "main.h"
  22. #include "paper.h"
  23. #include "postscri.h"
  24.  
  25. /********************************
  26.   defines
  27.  ********************************/
  28.  
  29. /* environment variables */
  30. #define        PRINTER        "PRINTER"        /* sets name of printer */
  31. #define        NENSCRIPT    "NENSCRIPT"        /* contains options */
  32.  
  33. /********************************
  34.   exports
  35.  ********************************/
  36. char *progname;
  37.  
  38. /********************************
  39.   usage
  40.  ********************************/
  41.  
  42. void usage ()
  43.  
  44. {
  45.   printf ("usage: %s -?12BGghlNnRrSsVWwZ -f font -F titlefont -b header -i filetitle -L lines -p filename -P printer -S classification -T papertype -t tabstop -# copies file...\n", progname);
  46.   exit (0);
  47. }
  48.  
  49. /*********************************
  50.  
  51. variables set by options
  52.  
  53.  *********************************/
  54.  
  55. static int  landscape = False;            /* True if in ladnscape mode, i.e. -r specified */
  56. static int  columns = 1;                /* number of columns to print with */
  57. static char *outputfilename = NULL;            /* name of output file, if still NULL after parsing args then use lpr */
  58. static char *bodyfont = NULL;            /* font to use for text */
  59. static char *titlefont = NULL;            /* font to use for titles */
  60. static int  wrap = True;                /* True if to wrap long lines */
  61. static int  titlesenabled = True;            /* True if page titles enables */
  62. static char *title = NULL;                /* set to title if specified */
  63. static int  copies = 1;                /* number of copies of each page */
  64. static int  gaudy = False;                /* enables gaudy mode */
  65. static int  force_lines = 0;                /* force number of lines per page */
  66. static char *classification = NULL;            /* security classification */
  67. static int  line_numbers = False;                    /* true if to display line numbers */
  68. static char *printername = DEF_PRINTER;        /* name of printer to use when output goes to lpr */
  69. static int  tabstop = 8;            /* tab stops */
  70. static int  passthroughflag = False;        /* if True, then check for %! to allow passthrough of raw postscript */
  71. static char *filetitle = NULL;                  /* set file title */
  72.  
  73. #ifdef US_VERSION
  74. static char *papertype = "US";
  75. #else
  76. static char *papertype = "A4";
  77. #endif
  78.  
  79.  
  80. /*
  81.  * forward declarations if in ANSI mode
  82.  */
  83.  
  84. #ifdef __STDC__
  85. char * get_string  (char **);
  86. void parse_options (int *, char ***);
  87. void parse_env     (char *);
  88.  
  89.  
  90. #endif
  91.  
  92.  
  93. /********************************
  94.   parse_options
  95.  ********************************/
  96.  
  97. #define    ARGC    (*argc)
  98. #define    ARGV    (*argv)
  99.  
  100. void parse_options (argc, argv)
  101.  
  102. int *argc;
  103. char ***argv;
  104.  
  105. {
  106.   char c;
  107.   char *s;
  108.   int i;
  109.  
  110.   /* parse the options */
  111.  
  112. next_argv:
  113.  while (--ARGC > 0 && (*++ARGV)[0] == '-')
  114.     while (c = *++ARGV[0])
  115.       switch (c) {
  116.  
  117. /* -? : print help message */
  118.         case '?' :
  119.         case 'h' :
  120.           usage ();
  121.           break;
  122.  
  123. /* -1 : single column mode */
  124.         case '1' :
  125.           columns = 1;
  126.           break;
  127.  
  128. /* -2 : double column mode */
  129.         case '2' :
  130.           columns = 2;
  131.           break;
  132.  
  133. /* -#: set number of copies */
  134.         case '#' :
  135.           if (*++ARGV[0])
  136.             copies = atoi (ARGV[0]);
  137.           else {
  138.             if (ARGC < 1)
  139.               fprintf (stderr, "%s: -# option requires argument\n", progname);
  140.             else {
  141.               --ARGC;
  142.               copies = atoi (*++ARGV);
  143.             }
  144.           }
  145.           if (copies < 1) {
  146.             fprintf (stderr, "%s: illegal number of copies specified - defaulting to one\n", progname);
  147.             copies = 1;
  148.           }
  149.           goto next_argv;
  150.           break;
  151.  
  152. /* -b: set page title */
  153.         case 'b' :
  154.           if (*++ARGV[0])
  155.             title = ARGV[0];
  156.           else {
  157.             if (ARGC < 1)
  158.               fprintf (stderr, "%s: -b option requires argument\n", progname);
  159.             else {
  160.               --ARGC;
  161.               title = *++ARGV;
  162.             }
  163.           }
  164.           goto next_argv;
  165.           break;
  166.  
  167. /* -f : set font to use for printing body */
  168.         case 'f' :
  169.           if (*++ARGV[0])
  170.             bodyfont = ARGV[0];
  171.           else {
  172.             if (ARGC < 1)
  173.               fprintf (stderr, "%s: -f option requires argument\n", progname);
  174.             else {
  175.               --ARGC;
  176.               bodyfont = *++ARGV;
  177.             }
  178.           }
  179.           goto next_argv;
  180.           break;
  181.  
  182. /* -N : display line numbers */
  183.         case 'N' :
  184.           line_numbers = True;
  185.           break;
  186.  
  187. /* -n : disable line numbers */
  188.         case 'n' :
  189.           line_numbers = False;
  190.           break;
  191.  
  192. /* -p: send to file rather than lpr */
  193.         case 'p' :
  194.           if (*++ARGV[0])
  195.             outputfilename = ARGV[0];
  196.           else {
  197.             if (ARGC < 1)
  198.               fprintf (stderr, "%s: -p option requires argument\n", progname);
  199.             else {
  200.               --ARGC;
  201.               outputfilename = *++ARGV;
  202.             }
  203.           }
  204.           goto next_argv;
  205.           break;
  206.  
  207. /* -r : landscape mode */
  208.         case 'r' :
  209.           landscape = True;
  210.           break;
  211.  
  212. /* -w : wrap mode */
  213.         case 'w' :
  214.           wrap = True;
  215.           break;
  216.  
  217. /* -Z : check for postscript passthrough mode */
  218.         case 'Z' :
  219.           passthroughflag = True;
  220.           break;
  221.  
  222. /* -B : disable page headings and disable gaudy mode */
  223.         case 'B' :
  224.           titlesenabled = False;
  225.           break;
  226.  
  227. /* -F : set font to use for printing titles */
  228.         case 'F' :
  229.           if (*++ARGV[0])
  230.             titlefont = ARGV[0];
  231.           else {
  232.             if (ARGC < 1)
  233.               fprintf (stderr, "%s: -F option requires argument\n", progname);
  234.             else {
  235.               --ARGC;
  236.               titlefont = *++ARGV;
  237.             }
  238.           }
  239.           goto next_argv;
  240.           break;
  241.  
  242. /* -g : disable gaudy mode */
  243.         case 'g' :
  244.           gaudy = False;
  245.           break;
  246.  
  247. /* -G : enable gaudy mode */
  248.         case 'G' :
  249.           gaudy = True;
  250.           break;
  251.  
  252. /* -i: set file title when inputting from stdin */
  253.         case 'i' :
  254.           if (*++ARGV[0])
  255.             filetitle = ARGV[0];
  256.           else {
  257.             if (ARGC < 1)
  258.               fprintf (stderr, "%s: -i option requires argument\n", progname);
  259.             else {
  260.               --ARGC;
  261.               filetitle = *++ARGV;
  262.             }
  263.           }
  264.           goto next_argv;
  265.           break;
  266.  
  267. /* -l : don't set number of lines of page, i.e. use maximum */
  268.         case 'l' :
  269.           force_lines = 0;
  270.           break;
  271.  
  272. /* -L : force number of lines per page */
  273.         case 'L' :
  274.           if (*++ARGV[0])
  275.             force_lines = atoi(ARGV[0]);
  276.           else {
  277.             if (ARGC < 1)
  278.               fprintf (stderr, "%s: -x option requires argument\n", progname);
  279.             else {
  280.               --ARGC;
  281.               force_lines = atoi (*++ARGV);
  282.             }
  283.           }
  284.       if (force_lines <= 0) {
  285.             fprintf (stderr, "%s: ignoring illegal arguement to -L option\n", progname);
  286.         force_lines = 0;
  287.           }
  288.           goto next_argv;
  289.           break;
  290.  
  291. /* -P: set printer name - overrides PRINTER environment variables */
  292.         case 'P' :
  293.           if (*++ARGV[0])
  294.             printername = ARGV[0];
  295.           else {
  296.             if (ARGC < 1)
  297.               fprintf (stderr, "%s: -P option requires argument\n", progname);
  298.             else {
  299.               --ARGC;
  300.               printername = *++ARGV;
  301.             }
  302.           }
  303.           goto next_argv;
  304.           break;
  305.  
  306. /* -R : portrait mode */
  307.         case 'R' :
  308.           landscape = False;
  309.           break;
  310.  
  311. /* -S: set security classification */
  312.         case 'S' :
  313.           if (*++ARGV[0])
  314.             classification = ARGV[0];
  315.           else {
  316.             if (ARGC < 1)
  317.               fprintf (stderr, "%s: -S option requires argument\n", progname);
  318.             else {
  319.               --ARGC;
  320.               classification = *++ARGV;
  321.             }
  322.           }
  323.           goto next_argv;
  324.           break;
  325.  
  326. /* -s : disable security classification printing */
  327.         case 's' :
  328.           classification = NULL;
  329.           break;
  330.  
  331.  
  332. /* -T: set paper size to either US or A4 */
  333.         case 'T' :
  334.           if (*++ARGV[0])
  335.             papertype = ARGV[0];
  336.           else {
  337.             if (ARGC < 1)
  338.               fprintf (stderr, "%s: -T option requires argument\n", progname);
  339.             else {
  340.               --ARGC;
  341.               papertype = *++ARGV;
  342.             }
  343.           }
  344.           goto next_argv;
  345.           break;
  346.  
  347. /* -t: set tab stop size */
  348.         case 't' :
  349.           if (*++ARGV[0])
  350.             s = ARGV[0];
  351.           else {
  352.             if (ARGC < 1) {
  353.               fprintf (stderr, "%s: -t option requires argument\n", progname);
  354.           s = 0;        /* We should flag the error in some way */
  355.             } else {
  356.               --ARGC;
  357.               s = *++ARGV;
  358.             }
  359.           }
  360.           if ((i = atoi (s)) <= 0) 
  361.             fprintf (stderr, "%s: illegal tab setting %s ignored\n", progname, s);
  362.           else
  363.             tabstop = i;
  364.           goto next_argv;
  365.           break;
  366.  
  367. /* -V : print version number */
  368.     case 'V' :
  369.           fputs (version_string,   stderr);
  370.           fputs ("\n",           stderr);
  371.           /* fputs (copyright_string, stderr); */
  372.           exit (0);
  373.           break;
  374.  
  375. /* -W : turn off wrap mode */
  376.         case 'W' :
  377.           wrap = False;
  378.           break;
  379.  
  380. /* single char option */
  381. /*        case 'x' :
  382.           allow_checkouts = True;
  383.           break;
  384. */
  385.  
  386. /* option with string */
  387. /*        case 'x' :
  388.           if (*++ARGV[0])
  389.             optionstring = ARGV[0];
  390.           else {
  391.             if (ARGC < 1)
  392.               fprintf (stderr, "%s: -x option requires argument\n", progname);
  393.             else {
  394.               --ARGC;
  395.               optionstring = *++ARGV;
  396.             }
  397.           }
  398.           goto next_argv;
  399.           break;
  400. */
  401.         default :
  402.           fprintf (stderr, "%s: unknown option %c\n", progname, c);
  403.           ARGC = 0;
  404.           break;
  405.       }
  406. }
  407.  
  408. /********************************
  409.   get_string
  410.     return the next string from the argument
  411.  ********************************/
  412.  
  413. char * get_string (str)
  414.  
  415. char **str;
  416.  
  417. #define    STR    (*str)
  418.  
  419. {
  420.   char *ret = NULL;
  421.   int  in_dquote, in_squote, in_bquote;
  422.   int  quote_count;
  423.  
  424.   /* skip leading whitespace */
  425.   while (*STR == ' ' ||
  426.          *STR == '\t')
  427.     STR++;
  428.  
  429.   /* return if end of string */
  430.   if (*STR == '\0')
  431.     return NULL;
  432.  
  433.   /* collect characters until end of string or whitespace */
  434.   in_dquote = -1;
  435.   in_squote = -1;
  436.   in_bquote = -1;
  437.   quote_count = 0;
  438.   ret = STR;
  439.   while (*STR != '\0' &&
  440.          (quote_count > 0 || (*STR != ' ' && *STR != '\t'))
  441.         ) {
  442.     switch (*STR) {
  443.       case '"':
  444.         in_dquote = -in_dquote;
  445.         quote_count += in_dquote;
  446.         break;
  447.  
  448.       case '\'':
  449.         in_squote = -in_squote;
  450.         quote_count += in_squote;
  451.         break;
  452.  
  453.       case '`':
  454.         in_bquote = -in_bquote;
  455.         quote_count += in_bquote;
  456.         break;
  457.  
  458.       case '\\':
  459.         if (STR[1] != '\0')
  460.           STR++;
  461.         break;
  462.     }
  463.     STR++;
  464.   }
  465.   if (*STR != '\0') {
  466.     *STR = '\0';
  467.     STR++;
  468.   }
  469.  
  470.   if (quote_count > 0)
  471.     fprintf (stderr, "unmatched quote in %s environment variable\n", NENSCRIPT);
  472.  
  473.   return ret;
  474. }
  475.  
  476.  
  477. /********************************
  478.   parse_env
  479.     process the options specified in the supplied string
  480.  ********************************/
  481.  
  482. void parse_env (env)
  483.  
  484. char *env;
  485.  
  486. {
  487.   int argc;
  488.   char *s;
  489.   char **argv;
  490.  
  491.   if (env == NULL)
  492.     return;
  493.  
  494.   /* insert a "fake" argv[0] which corresponds to the real
  495.      argv[0] passed to main. The allows us to use same routine
  496.      for handling the real arguments */
  497.   argv = (char **)malloc (sizeof (char *));
  498.   argc = 1;
  499.   argv[0] = progname;
  500.  
  501.   /* split the single environment string into separate strings so we can pass
  502.      them to parse_options */
  503.   while ((s = get_string (&env)) != NULL) {
  504.     argv = (char **)realloc ((void *)argv, (argc+1) * sizeof (char *));
  505.     argv[argc] = s;
  506.     argc++;
  507.   }
  508.  
  509.   /* parse the options */
  510.   parse_options (&argc, &argv);
  511. }
  512.  
  513. /********************************
  514.   passthrough
  515.  ********************************/
  516.  
  517. static void passthrough (input, output)
  518.  
  519. FILE * input;
  520. FILE * output;
  521.  
  522. {
  523.   char buff [512];
  524.   int  len;
  525.  
  526.   while ((len = fread (buff, 1, 512, input)) > 0)
  527.     fwrite (buff, 1, len, output);
  528. }
  529.  
  530.  
  531. /********************************
  532.   main
  533.  ********************************/
  534.  
  535. int main (argc, argv)
  536.  
  537. int argc;
  538. char *argv[];
  539.  
  540. {
  541.   char *env;
  542.   char cmd[1024];
  543.   struct PaperMetrics * papermetrics;
  544.   int i;
  545.   int ch1;
  546.   int ch2;
  547.  
  548.  
  549.   FILE *outputstream;                /* opened output stream - either file or lpr */
  550.   FILE *inputstream;                /* opened input stream, 0 if max */
  551.  
  552.   /* extract the program name */
  553.   if ((progname = strrchr (argv[0], '/')) == NULL)
  554.     progname = argv[0];
  555.   else
  556.     progname++;
  557.  
  558.   /* get the printer environment variable */
  559.   if ((env = getenv (PRINTER)) != NULL)
  560.     printername = env;
  561.  
  562.   /* handle the NENSCRIPT environment variable */
  563.   if ((env = getenv (NENSCRIPT)) != NULL)
  564.     parse_env (STRDUP(env));
  565.  
  566.   /* parse arguments */
  567.   parse_options (&argc, &argv);
  568.  
  569.   /* open either the output file or a pipe to lpr */
  570.   if (outputfilename != NULL) {
  571.     if (strcmp (outputfilename, "-") == 0)
  572.       outputstream = stdout;
  573.     else if ((outputstream = fopen (outputfilename, "w")) == NULL) {
  574.       perror (outputfilename);
  575.       exit (1);
  576.     }
  577.   } else {
  578. #ifdef MSDOS
  579.     if ((outputstream = fopen (printername, "w")) == NULL) {
  580.       perror (printername);
  581.       exit (1);
  582.     }
  583. #else /* MSDOS */
  584. #ifdef AMIGA
  585.     if ((outputstream = fopen ("LPR:", "w")) == NULL) {
  586.       perror ("lpr:");
  587.       exit (1);
  588.     }
  589. #else  /* Amiga */
  590.     sprintf (cmd, "%s %s", LPR, printername);
  591.     if ((outputstream = popen (cmd, "w")) == NULL) {
  592.       perror (LPR);
  593.       exit (1);
  594.     }
  595. #endif /* Amiga */
  596. #endif /* MSDOS */
  597.   }
  598.  
  599.   /* can't be in passthrough mode with more than one argument */
  600.   if (argc > 1 && passthroughflag) {
  601.     fprintf (stderr, "%s: ignoring -Z flag as there is more than one argument", progname);
  602.     passthroughflag = False;
  603.   }
  604.  
  605.   /* if in passthrough mode, open the input stream and check for %! */
  606.   if (passthroughflag) {
  607.     if (argc < 1)
  608.       inputstream = stdin;
  609.     else if ((inputstream = fopen (*argv, "r")) == NULL) {
  610.       perror (*argv);
  611.       exit (1);
  612.     }
  613.     ch1 = fgetc (inputstream);
  614.     ch2 = fgetc (inputstream);
  615.     ungetc (ch2, inputstream);
  616.     ungetc (ch1, inputstream);
  617.     if (ch1 == '%' && ch2 == '!') {
  618.       passthrough (inputstream, outputstream);
  619.       exit (0);
  620.     }
  621.   } else
  622.     inputstream = NULL;
  623.  
  624.   /* check the paper type and get ptr to record */
  625.   papermetrics = NULL;
  626.   for (i = 0; PaperTypes[i].Name != NULL; i++)
  627.     if (STRICMP ((papermetrics = &PaperTypes[i])->Name, papertype) == 0)
  628.       break;
  629.  
  630.   /* if the papermetric was not set, give error */
  631.   if (PaperTypes[i].Name == NULL) {
  632.     fprintf (stderr, "%s: paper type %s not known\n", progname, papertype);
  633.     exit (1);
  634.   }
  635.  
  636.   /* set up the fonts */
  637.   if (bodyfont == NULL)
  638.     bodyfont = (columns == 2 && landscape) ? papermetrics->LandscapeFont : papermetrics->PortraitFont;
  639.  
  640.   if (titlefont == NULL)
  641.     titlefont = papermetrics->TitleFont;
  642.  
  643.   /* display the header */
  644.   StartJob (outputstream,
  645.             *argv,
  646.             landscape,
  647.             columns,
  648.             bodyfont,
  649.             titlefont,
  650.             wrap,
  651.             titlesenabled,
  652.             title,
  653.             copies,
  654.             gaudy,
  655.             force_lines,
  656.             classification,
  657.             papermetrics,
  658.         tabstop);
  659.  
  660.   /* if no arguments, then accept stdin */
  661.   if (argc < 1)
  662.     print_file (stdin, outputstream, (filetitle ? filetitle : "stdin"), line_numbers);
  663.   else for (;argc > 0;argc--) {
  664.     if (inputstream == NULL && (inputstream = fopen (*argv, "r")) == NULL)
  665.       perror (*argv);
  666.     else {
  667.       print_file (inputstream, outputstream, (filetitle ? filetitle : *argv), line_numbers);
  668.       fclose(inputstream);
  669.       inputstream = NULL;
  670.     }
  671.     argv++;
  672.   }
  673.  
  674.   /* output trailer */
  675.   EndJob (outputstream);
  676.  
  677.   /* finished */
  678.   return (0);
  679. }
  680.